package table

import (
	"TD-UI/internal/consts"
	"TD-UI/internal/logic/link"
	"TD-UI/internal/model"
	"TD-UI/internal/service"
	"context"
	"fmt"
	"log"
	"strconv"
)

func init() {
	service.RegisterTable(New())
}

type sTable struct{}

func New() service.ITable {
	return &sTable{}
}

func (s *sTable) GetTable(ctx context.Context, req model.TableReq) (res model.TableRes, err error) {
	taos, err := link.OpenTasos(req.LinkId, req.DbName, true)
	if err != nil {
		panic(err)
	}
	defer taos.Close()

	sql := "SHOW TABLES"
	if req.SupperTable {
		sql = "SHOW STABLES"
	}
	result, err := taos.Query(sql)
	defer result.Close()
	var tables = make([]string, 0)
	for result.Next() {
		var tbName string
		err = result.Scan(&tbName)
		if err != nil {
			log.Println("failed to scan result, err:", err)
		}
		log.Println(tbName)
		tables = append(tables, tbName)
	}
	log.Println(tables)
	res.Result = tables
	return
}

func (s *sTable) GetTableData(ctx context.Context, req model.TableDataReq) (res model.TableDataRes, err error) {
	//TODO implement me
	taos, err := link.OpenTasos(req.LinkId, req.DbName, true)
	if err != nil {
		panic(err)
	}
	defer taos.Close()

	countSql := "SELECT COUNT(*) FROM " + req.DbName + "." + req.TableName
	resultSql := "SELECT * FROM " + req.DbName + "." + req.TableName
	fmt.Println(countSql, "--", resultSql)
	resultCount, err := taos.Query(countSql)
	defer resultCount.Close()
	fmt.Println(resultCount)
	var count int
	for resultCount.Next() {
		err = resultCount.Scan(&count)
		if err != nil {
			log.Println("failed to scan result, err:", err)
		}
	}
	var columns = make([]string, 0)
	var resultData = make([]map[string]string, 0)
	if count > 0 {
		columnsData := model.TableDataReq{
			LinkId:     req.LinkId,
			DbName:     req.DbName,
			TableName:  req.TableName,
			StableName: req.StableName,
		}
		tableColumns, err := s.GetTableColumns(ctx, columnsData)
		if err != nil {
			panic(err)
		}
		resultSql += " ORDER BY " + tableColumns.TableInfo[0].Field + " DESC"
		offset := (req.PageSize - 1) * req.PageNum
		resultSql = resultSql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(req.PageNum)
		result, err := taos.Query(resultSql)
		defer result.Close()
		if err != nil {
			log.Println("failed to query result, err:", err)
		}
		//var data = make([]interface{}, 0)

		columns, err = result.Columns()
		if err != nil {
			log.Println("failed to query columns, err:", err)
		}
		fmt.Println(columns)

		vals := make([][]byte, len(columns))
		scans := make([]interface{}, len(columns))
		for k := range columns {
			scans[k] = &vals[k]
		}
		//resultMap := make(map[int]map[string]string)

		for result.Next() {
			err = result.Scan(scans...)
			if err != nil {
				log.Println("failed to scan result, err:", err)
			}
			row := make(map[string]string) //每行数据
			for k, v := range vals {
				key := columns[k]
				row[key] = string(v)
			}
			//resultMap[i] = row //装入结果集中
			resultData = append(resultData, row)
		}

	}
	res.Total = count
	res.Columns = columns
	res.Datas = resultData
	return
}

func (s *sTable) GetTableColumns(ctx context.Context, req model.TableDataReq) (res model.TableDataRes, err error) {
	//TODO implement me
	taos, err := link.OpenTasos(req.LinkId, req.DbName, true)
	if err != nil {
		panic(err)
	}

	sqlQuery := fmt.Sprintf("DESCRIBE `%s`.`%s`", req.DbName, req.TableName)
	result, err := taos.Query(sqlQuery)
	if err != nil {
		log.Println("failed to scan result, err:", err)
	}
	defer result.Close()
	table := make([]model.ColumnInfo, 0)
	for result.Next() {
		tableInfo := *new(model.ColumnInfo)
		if err = result.Scan(&tableInfo.Field, &tableInfo.Type, &tableInfo.Length, &tableInfo.Note); err != nil {
			log.Println("failed to query TDengine, err:", err)
			return
		}
		table = append(table, tableInfo)
	}
	res.TableInfo = table
	return
}

func (s *sTable) QueryTableData(ctx context.Context, req model.TableDataQueryReq) (res model.TableDataRes, err error) {
	taos, err := link.OpenTasos(req.LinkId, req.DbName, true)
	if err != nil {
		panic(err)
	}
	defer taos.Close()
	result, err := taos.Query(req.Sql)
	defer result.Close()
	if err != nil {
		log.Println("failed to query result, err:", err)
	}
	//var data = make([]interface{}, 0)

	var columns = make([]string, 0)
	var resultData = make([]map[string]string, 0)

	columns, err = result.Columns()
	if err != nil {
		log.Println("failed to query columns, err:", err)
	}
	fmt.Println(columns)

	vals := make([][]byte, len(columns))
	scans := make([]interface{}, len(columns))
	for k := range columns {
		scans[k] = &vals[k]
	}
	//resultMap := make(map[int]map[string]string)

	for result.Next() {
		err = result.Scan(scans...)
		if err != nil {
			log.Println("failed to scan result, err:", err)
		}
		row := make(map[string]string) //每行数据
		for k, v := range vals {
			key := columns[k]
			row[key] = string(v)
		}
		resultData = append(resultData, row)
	}
	res.Columns = columns
	res.Datas = resultData
	return
}

func (s *sTable) DelTable(ctx context.Context, req model.TableDelReq) (res model.TableRes, err error) {
	taos, err := link.OpenTasos(req.LinkId, req.DbName, true)
	if err != nil {
		panic(err)
	}
	defer taos.Close()
	sql := fmt.Sprintf("DROP TABLE IF EXISTS %s.%s", req.DbName, req.TableName)
	log.Println(sql)
	_, err = taos.Exec(sql)
	if err != nil {
		panic(err)
	}
	return
}

type Ddl struct {
	Table       string
	CreateTable string
}

func (s *sTable) DdlTable(ctx context.Context, req model.TableDdlReq) (res model.TableRes, err error) {
	//TODO implement me
	taos, err := link.OpenTasos(req.LinkId, req.DbName, true)
	if err != nil {
		panic(err)
	}
	defer taos.Close()
	sql := fmt.Sprintf("SHOW CREATE TABLE %s", req.TableName)
	result, err := taos.Query(sql)
	var createSql string
	for result.Next() {
		ddl := *new(Ddl)
		_ = result.Scan(&ddl.Table, &ddl.CreateTable)
		createSql = ddl.CreateTable
	}
	res.Result = createSql
	return
}

func (s *sTable) CreateTable(ctx context.Context, req model.TableCreateReq) (res model.TableRes, err error) {
	taos, err := link.OpenTasos(req.LinkId, req.DbName, true)
	if err != nil {
		panic(err)
	}
	defer taos.Close()
	var tableType string
	if req.IsSupper {
		tableType = "STABLE"
	} else {
		tableType = "TABLE"
	}
	sql := fmt.Sprintf("CREATE %s %s.%s ", tableType, req.DbName, req.TableName)
	if !req.IsSupper && req.STableName != "" {
		sql += " USING " + req.STableName
	}
	sql += "("
	// 封装字段
	tagsSql := " TAGS ("

	isEven := func(filed model.TableFiledReq, attribute string) bool {
		return filed.FieldAttribute == attribute
	}

	fileds := filter(req.Fields, consts.TableAttributeField, isEven)
	tags := filter(req.Fields, consts.TableAttributeTag, isEven)

	for i, field := range fileds {
		filedLen := consts.TableFiledDefaultLen[field.FieldType]
		if filedLen == consts.TableCustomFiledLen {
			sql += field.FieldName + " " + field.FieldType + "(" + strconv.Itoa(field.FieldLen) + ")"
		} else {
			sql += field.FieldName + " " + field.FieldType
		}

		if i < len(fileds)-1 {
			sql += ","
		} else {
			sql += ")"
		}
	}

	for i, field := range tags {
		filedLen := consts.TableFiledDefaultLen[field.FieldType]
		if filedLen == consts.TableCustomFiledLen {
			tagsSql += field.FieldName + " " + field.FieldType + "(" + strconv.Itoa(field.FieldLen) + ")"
		} else {
			tagsSql += field.FieldName + " " + field.FieldType
		}

		if i < len(tags)-1 {
			tagsSql += ","
		} else {
			tagsSql += ")"
		}
	}

	if req.IsSupper {
		sql += tagsSql
	}
	fmt.Println(sql)

	_, err = taos.Exec(sql)
	if err != nil {
		panic(err)
	}
	return
}

func filter(in []model.TableFiledReq, attribute string, even func(model.TableFiledReq, string) bool) []model.TableFiledReq {
	result := make([]model.TableFiledReq, 0)
	for _, v := range in {
		if even(v, attribute) {
			result = append(result, v)
		}
	}
	return result
}

func (s *sTable) ExecSqlTableData(ctx context.Context, req model.TableExecSqlReq) (res model.TableRes, err error) {
	taos, err := link.OpenTasos(req.LinkId, req.DbName, true)
	if err != nil {
		panic(err)
	}
	defer taos.Close()
	_, err = taos.Exec(req.Sql)
	res.Result = true
	if err != nil {
		log.Println("failed to query result, err:", err)
		res.Result = false
	}
	return
}
